package cn.trigram.date;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.MonthDay;
import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

/**
 * 时间日期解析器
 *
 * @version 1.0.0
 * @date 2022/07/22 14:32:57
 * @since 1.0.0
 */
public class DateTimeResolver {

    private final LocalDateTime ldt;

    public DateTimeResolver(Date d) {

        Objects.requireNonNull(d, "日期参数不能为空");
        this.ldt = LocalDateTime.ofInstant(d.toInstant(), ZoneId.systemDefault());
    }

    public DateTimeResolver(LocalDateTime ldt) {

        Objects.requireNonNull(ldt, "日期参数不能为空");
        this.ldt = ldt;
    }

    /**
     * 获取年份
     *
     * @return int
     */
    public int getYear() {

        return ldt.getYear();
    }

    /**
     * 是否是闰年
     *
     * @return int
     */
    public boolean isLeapYear() {

        return Year.from(ldt).isLeap();
    }

    /**
     * 获取在当前年份中的月份
     *
     * @return int  从1-12
     */
    public int getMonth() {

        return ldt.getMonth().getValue();
    }

    /**
     * 获取在当前年份中的周数
     *
     * @return int  从1-52
     */
    public int getWeek() {

        return ldt.get(ChronoField.ALIGNED_WEEK_OF_YEAR);
    }

    /**
     * 在当前年份中的天数
     *
     * @return int 从1-365/366
     */
    public int getDayOfYear() {

        return ldt.getDayOfYear();
    }

    /**
     * 在当前月份中的天数
     *
     * @return int 从1-31
     */
    public int getDayOfMonth() {

        return ldt.getDayOfMonth();
    }

    /**
     * 在当前周中的天数
     *
     * @return int  从星期一开始，1-7
     */
    public int getDayOfWeek() {

        return ldt.getDayOfWeek().getValue();
    }

    /**
     * 提供了一个本地化的月份文本形式，如一月，二月等
     */
    public String getLocalizedMonth() {

        return ldt.getMonth().getDisplayName(TextStyle.FULL_STANDALONE, Locale.getDefault());
    }

    /**
     * 提供了一个本地化的每周中的天数的文本形式，如星期一、星期二等
     */
    public String getLocalizedDayOfWeek() {

        return DayOfWeek.from(ldt).getDisplayName(TextStyle.FULL_STANDALONE, Locale.getDefault());
    }

    public Instant toInstant() {

        return ldt.atZone(ZoneId.systemDefault()).toInstant();
    }

    public Year toYear() {

        return Year.from(ldt);
    }

    public YearMonth toYearMonth() {

        return YearMonth.from(ldt);
    }

    public Month toMonth() {

        return Month.from(ldt);
    }

    public MonthDay toMonthDay() {

        return MonthDay.from(ldt);
    }

    /**
     * 当月第一天在今年的天数
     *
     * @return int
     */
    public int getFirstDayOfMonthInYear() {
        return toMonth().firstDayOfYear(isLeapYear());
    }

    /**
     * 获取当前季度的第一个月
     *
     * @return {@link Month }
     */
    public Month getFirstMonthOfQuarter() {
        return toMonth().firstMonthOfQuarter();
    }

    /**
     * 获取当前季度的总天数
     *
     * @return long
     */
    public long getQuarterDays() {
        return Duration.between(
                ldt.withMonth(ldt.getMonth().firstMonthOfQuarter().getValue())
                        .withDayOfMonth(1).toLocalDate().atTime(0, 0, 0, 0),
                ldt.withMonth(ldt.getMonth().firstMonthOfQuarter().getValue()).plusMonths(3L)
                        .withDayOfMonth(1).toLocalDate().atTime(23, 59, 59, 999999999)
        ).toDays();
    }

    /**
     * 获取当前月份的总天数
     *
     * @return long
     */
    public long getMonthDays() {
        return Duration.between(
                ldt.withDayOfMonth(1).toLocalDate().atStartOfDay(),
                ldt.withDayOfMonth(1).plusMonths(1L).toLocalDate().atStartOfDay()
        ).toDays();
    }

    /**
     * 获取当前年份的总天数
     *
     * @return long
     */
    public long getYearDays() {
        return Duration.between(
                ldt.withDayOfYear(1).toLocalDate().atStartOfDay(),
                ldt.withDayOfYear(1).plusYears(1L).toLocalDate().atStartOfDay()
        ).toDays();
    }

    /**
     * 第几季度
     *
     * @return int 取值1、2、3、4
     */
    public int getQuarter() {
        int months = toMonth().firstMonthOfQuarter().getValue();
        Double ceil = Math.ceil(months / 3d);
        return ceil.intValue();
    }

    @Override
    public String toString() {
        return this.ldt.toString();
    }
}
